local module = {}
module.name = "CombatText"
module.Init = function()
	if not SCDB.modules[module.name] then return end
	if SCDB[module.name] == nil then SCDB[module.name] = {} end
	if SCDB[module.name]["Show Icons"] == nil then SCDB[module.name]["Show Icons"] = true end
	if SCDB[module.name]["Width"] == nil then SCDB[module.name]["Width"] = 200 end
	if SCDB[module.name]["Height"] == nil then SCDB[module.name]["Height"] = 200 end

	COMBAT_TEXT_DEFLECT = "Deflect"
	COMBAT_TEXT_REFLECT = "Reflect"
	COMBAT_TEXT_IMMUNE = "Immune"
	COMBAT_TEXT_RESIST = "Resist"
	COMBAT_TEXT_ABSORB = "Absorb"
	COMBAT_TEXT_BLOCK = "Block"
	COMBAT_TEXT_DODGE = "Dodge"
	COMBAT_TEXT_PARRY = "Parry"
	COMBAT_TEXT_EVADE = "Evade"
	COMBAT_TEXT_MISS = "Miss"

	DEFLECT = "Deflect"
	REFLECT = "Reflect"
	IMMUNE = "Immune"
	RESIST = "Resist"
	ABSORB = "Absorb"
	BLOCK = "Block"
	DODGE = "Dodge"
	PARRY = "Parry"
	EVADE = "Evade"
	MISS = "Miss"

	BLOCK_TRAILER = "(Block %d)"
	ABSORB_TRAILER = "(Absorb %d)"
	RESIST_TRAILER = "(Resist %d)"

	ENTERING_COMBAT = "+COMBAT+"
	LEAVING_COMBAT = "-COMBAT-"
	HEALTH_LOW = "Low Health"

	if SCDB[module.name]["Raid announce"] == nil then SCDB[module.name]["Raid announce"] = false end
	if SCDB[module.name]["Party announce"] == nil then SCDB[module.name]["Party announce"] = false end
	if SCDB[module.name]["Yell announce"] == nil then SCDB[module.name]["Yell announce"] = true end
	if SCDB[module.name]["Say announce"] == nil then SCDB[module.name]["Say announce"] = false end
	if SCDB[module.name]["Play sounds"] == nil then SCDB[module.name]["Play sounds"] = true end
	local opts = SCDB[module.name]

	local lastKillTime = 0
	local killingStreak = 0
	local multiKill = 0
	local MULTI_KILL_HOLD_TIME = 11.5
	local bit_band = bit.band
	local bit_bor = bit.bor
	local pendingSound

	local spreeSounds = {
		[3] = "Killing_Spree",
		[4] = "Dominating",
		[5] = "Mega_Kill",
		[6] = "Unstoppable",
		[7] = "Wicked_Sick",
		[8] = "Monster_Kill",
		[9] = "Ludicrous_Kill",
		[10] = "God_Like",
		[11] = "Holy_Shit"
	}

	local multiSounds = {
		[2] = "Double_Kill",
		[3] = "Triple_Kill",
	}
	
	local path = "Interface\\AddOns\\" .. addonName .. "\\media\\sounds\\%s.mp3"
	
	local function hasFlag(flags, flag)
		return bit_band(flags, flag) == flag
	end

	-- by Evl
	local playSounds = function()
		local multiFileName = multiSounds[math.min(3, multiKill)]
		local spreeFileName = spreeSounds[math.min(11, killingStreak)]

		if multiFileName then
			PlaySoundFile(string.format(path, multiFileName))
		end

		if spreeFileName then
			local spreeFilePath = string.format(path, spreeFileName)

			if not multiFileName then
				PlaySoundFile(spreeFilePath)
			else
				pendingSound = spreeFilePath
			end
		end
	end

	local extraCombatText = CreateFrame("Frame")
	extraCombatText:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	extraCombatText:RegisterEvent("PLAYER_DEAD")
	extraCombatText:RegisterEvent("ADDON_LOADED")
	extraCombatText:SetScript("OnEvent", function(self, event, ...)
		if event == "COMBAT_LOG_EVENT_UNFILTERED" then
			local timestamp, eventType, _, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
			-- Killing blows
			if eventType == "PARTY_KILL" and hasFlag(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) and hasFlag(destFlags, COMBATLOG_OBJECT_TYPE_PLAYER) then
				if COMBAT_TEXT_TYPE_INFO then
					if SCDB[module.name]["Raid announce"] then
						SendChatMessage("Killing Blow! (" .. destName .. ")", "RAID")
					end
					if SCDB[module.name]["Party announce"] then
						SendChatMessage("Killing Blow! (" .. destName .. ")", "PARTY")
					end
					if SCDB[module.name]["Yell announce"] then
						SendChatMessage("Killing Blow! (" .. destName .. ")", "YELL")
					end
					if SCDB[module.name]["Say announce"] then
						SendChatMessage("Killing Blow! (" .. destName .. ")", "SAY")
					end
				end

				local now = GetTime()
		
				if lastKillTime + MULTI_KILL_HOLD_TIME > now then
					multiKill = multiKill + 1
				else
					multiKill = 1
				end
		
				lastKillTime = now
				killingStreak = killingStreak + 1
				if opts["Play sounds"] then
					playSounds()
				end
				
			-- Interrupts
			elseif eventType == "SPELL_INTERRUPT" and hasFlag(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) then
				local extraSpellID, extraSpellName, extraSpellSchool = select(13, ...)
				if SCDB[module.name]["Raid announce"] then
					SendChatMessage(format("%s Interrupted!", GetSpellLink(extraSpellID)), "RAID")
				end
				if SCDB[module.name]["Party announce"] then
					SendChatMessage(format("%s Interrupted!", GetSpellLink(extraSpellID)), "PARTY")
				end
				if SCDB[module.name]["Yell announce"] then
					SendChatMessage(format("%s Interrupted!", GetSpellLink(extraSpellID)), "YELL")
				end
				if SCDB[module.name]["Say announce"] then
					SendChatMessage(format("%s Interrupted!", GetSpellLink(extraSpellID)), "SAY")
				end
			end
		elseif event == "PLAYER_DEAD" then
			killingStreak = 0
		end
	end)
	
	extraCombatText:SetScript("OnUpdate", function(self, elapsed)
		if self.lastUpdate == nil then self.lastUpdate = 0 end
		self.lastUpdate = self.lastUpdate + elapsed
		if self.lastUpdate > 2 then
			self.lastUpdate = 0
			if pendingSound then
				PlaySoundFile(pendingSound)
				pendingSound = nil
			end
		end
	end)
	
	
	local fScroll = CreateFrame("Frame", "fScroll", UIParent)
	
	local CRIT_SIZE = 24
	local TEXT_SIZE = 16
	local ANI_SPEED = 5
	
	function fScroll:Make(name, x, y, w, h)
		if name and not _G[name] then
			local scroll = CreateFrame("Frame", "fScroll_"..name, UIParent)
			scroll:SetPoint("BOTTOMLEFT", x, y)
			scroll:SetSize(w, h)
			scroll.frames = {}
			if not fScroll.scrolls then fScroll.scrolls = {} end
			fScroll.scrolls[name] = scroll
			if UIMovableFrames then tinsert(UIMovableFrames, scroll) end
		else
			return
		end
	end

	function fScroll:Add(msg, crit, name, color, icon)
		if fScroll.scrolls[name] == nil then return end
		local curframe
		local frames = fScroll.scrolls[name].frames
		local parent = fScroll.scrolls[name]
		for i=1,#frames do
			if frames[i].using == false then
				curframe = frames[i]
				break
			end
		end
		
		if curframe == nil then	
			curframe = CreateFrame("Frame", nil, fScroll.scrolls[name]) 
			curframe:SetSize(1, 1)
			curframe:SetPoint("BOTTOM")
			tinsert(frames, curframe)
		end
		
		if not curframe.txt then 
			curframe.txt = curframe:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
			curframe.txt:SetPoint("CENTER")
			curframe.icon = curframe:CreateTexture(nil, "OVERLAY")
			curframe.icon:SetSize(18, 18)
			curframe.icon:SetPoint("LEFT", curframe.txt, "RIGHT", 5, 0)
			curframe.icon:SetTexCoord(.1,.9,.1,.9)
		end
		
		curframe:SetAlpha(0)
		curframe.using = true
		
		if crit == true then
			curframe.txt:SetFont(curframe.txt:GetFont(), CRIT_SIZE, "OUTLINE")
		else
			curframe.txt:SetFont(curframe.txt:GetFont(), TEXT_SIZE, "OUTLINE")
		end
		
		if color then
			curframe.txt:SetTextColor(color.r or color[1] or 1, color.g or color[2] or 1, color.b or color[3] or 1)
		else
			curframe.txt:SetTextColor(1,1,1)
		end
		
		if icon then
			curframe.icon:SetTexture(icon)
		else
			curframe.icon:SetTexture(nil)
		end
		
		curframe.txt:SetText(msg)
		
		curframe.animation = curframe:CreateAnimationGroup()
		
		curframe.time = GetTime()
		
		curframe.speed = ANI_SPEED - random(0,1)
		
		local alpha1 = curframe.animation:CreateAnimation("Alpha")
		alpha1:SetChange(1)
		alpha1:SetDuration(curframe.speed/4)
		
		local alpha2 = curframe.animation:CreateAnimation("Alpha")
		alpha2:SetStartDelay(curframe.speed/2)
		alpha2:SetChange(-1)
		alpha2:SetDuration(curframe.speed/4)

		local move = curframe.animation:CreateAnimation("Translation")
		move:SetDuration(curframe.speed)
		move:SetOffset(0, parent:GetHeight())
		move:SetScript("OnFinished", function(self, ...)
			curframe.using = false
		end)
		
		curframe.animation:Play()
	end
	
		
		
	local shcoolcolor = {
		[1]  = {1, 1, 0}, -- physical
		[2]  = {1, .9, .5}, -- holy
		[4]  = {1, .5, }, -- fire
		[8]  = {.3, 1, .7}, -- nature
		[16] = {.5, 1, 1}, -- frost
		[32] = {.5, .5, 1}, -- shadow
		[64] = {1, .5, 1}, -- arcane
	}
	local filterGuard = COMBATLOG_OBJECT_CONTROL_PLAYER + COMBATLOG_OBJECT_TYPE_GUARDIAN

	local OnEvent = function(self, event, ...)
		if event == "PLAYER_REGEN_ENABLED" then
			fScroll:Add(LEAVING_COMBAT, true, "Info", {1,0,0})
		elseif event == "PLAYER_REGEN_DISABLED" then
			fScroll:Add(ENTERING_COMBAT, true, "Info", {1,0,0}) 
		elseif event == "COMBAT_LOG_EVENT_UNFILTERED" then
			local timestamp, eventType, hideCaster, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
			if bit.band(destFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) == 0 then return end
			
			--Incoming heal
			
			if eventType=="SPELL_HEAL" or eventType=="SPELL_PERIODIC_HEAL" then
				local spellId, _, spellSchool, amount, _, _, _, _, absorbed, critical = select(10, ...)
				if not amount then return end
				fScroll:Add("+"..amount, _, "IncomingHeal", shcoolcolor[spellSchool] or {0.15, 1, 0.15}, GetSpellTexture(spellId))
			end		
			
			--Incoming damage
			
			if eventType=="SWING_DAMAGE" then
				local amount, _, _, _, _, absorbed, critical = select(10, ...)
				if not amount then return end
				fScroll:Add(absorbed and "-"..amount.."("..absorbed.." absorbed)" or "-"..amount, critical, "IncomingDamage", shcoolcolor[1], PET_ATTACK_TEXTURE)
			elseif eventType=="RANGE_DAMAGE" or eventType=="SPELL_DAMAGE" or eventType=="SPELL_PERIODIC_DAMAGE" or eventType=="DAMAGE_SHIELD" then
				local spellId, _, spellSchool, amount, _, _, _, _, absorbed, critical = select(10, ...)
				if not amount then return end
				fScroll:Add(absorbed and "-"..amount.."("..absorbed.." absorbed)" or "-"..amount, critical, "IncomingDamage", shcoolcolor[spellSchool] or shcoolcolor[1], GetSpellTexture(spellId))
			elseif eventType=="SWING_MISSED" then
				local missType = select(10, ...)
				fScroll:Add(missType, _, "IncomingDamage", shcoolcolor[1], PET_ATTACK_TEXTURE)
			elseif eventType=="RANGE_MISSED" or eventType=="SPELL_MISSED" then
				local spellId, _, spellSchool, missType = select(10, ...)
				fScroll:Add(missType, _, "IncomingDamage", shcoolcolor[spellSchool] or shcoolcolor[1], GetSpellTexture(spellId))
			end
		end
	end

	local addon = CreateFrame("Frame")
	addon:RegisterEvent("COMBAT_TEXT_UPDATE")
	addon:RegisterEvent("PLAYER_REGEN_ENABLED")
	addon:RegisterEvent("PLAYER_REGEN_DISABLED")
	addon:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	addon:SetScript("OnEvent", OnEvent)

	CombatText:SetScript("OnUpdate", nil)
	CombatText:SetScript("OnEvent", nil)
	CombatText:UnregisterAllEvents()
	
	
	fScroll:Make("Info", 100, 100, SCDB[module.name]["Width"] or 200, SCDB[module.name]["Height"] or 200)
	fScroll:Make("IncomingHeal", 100, 100, SCDB[module.name]["Width"] or 200, SCDB[module.name]["Height"] or 200)
	fScroll:Make("IncomingDamage", 100, 100, SCDB[module.name]["Width"] or 200, SCDB[module.name]["Height"] or 200)
end
tinsert(SuperClassic.modules, module) -- finish him!